package com.pt.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pt.common.constant.TorrentConstant;
import com.pt.entity.Peer;
import com.pt.entity.Torrent;
import com.pt.mapper.PeerMapper;
import com.pt.service.PeerService;
import com.pt.service.TorrentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.beans.factory.annotation.Autowired;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.Collections;

@Service
@Slf4j
public class PeerServiceImpl extends ServiceImpl<PeerMapper, Peer> implements PeerService {
    
    @Autowired
    private PeerMapper peerMapper;
    
    @Autowired
    private TorrentService torrentService;
    
    public PeerServiceImpl(@Lazy TorrentService torrentService) {
        this.torrentService = torrentService;
    }
    
    @Override
    @Transactional
    public void updatePeerStatus(String infoHash, Long userId, String ip, Integer port,
                               Long uploaded, Long downloaded, Long left, String event,
                               String userAgent) {
        log.info("更新peer状态 - infoHash: {}, userId: {}, ip: {}, port: {}, event: {}, left: {}", 
            infoHash, userId, ip, port, event, left);
        
        // 获取种子信息
        Torrent torrent = torrentService.lambdaQuery()
                .eq(Torrent::getInfoHash, infoHash)
                .one();
        if (torrent == null) {
            log.warn("种子不存在 - infoHash: {}", infoHash);
            return;
        }
        
        // 查找或创建peer记录
        Peer peer = lambdaQuery()
                .eq(Peer::getTorrentId, torrent.getId())
                .eq(Peer::getUserId, userId)
                .one();

        if (peer == null) {
            peer = new Peer();
            peer.setTorrentId(torrent.getId());
            peer.setUserId(userId);
            peer.setPeerId(infoHash); // 使用info_hash作为peer_id
            peer.setIp(ip);
            peer.setPort(port);
            peer.setUploaded(uploaded);
            peer.setDownloaded(downloaded);
            peer.setLeft(left);
            peer.setSeeder(false);
            peer.setLastAction(LocalDateTime.now());
            peer.setUserAgent(userAgent);
            peer.setInfoHash(infoHash);
            peer.setStatus(1); // 初始状态为下载中
            peer.setLastAnnounceTime(System.currentTimeMillis());
            baseMapper.insert(peer);
            log.info("创建新的peer记录 - userId: {}, torrentId: {}", userId, torrent.getId());
        }
        
        // 更新peer状态
        boolean isSeeder = left == 0;
        int status;
        
        if ("stopped".equals(event)) {
            status = 0; // 停止
            log.info("peer停止 - userId: {}, status: {}", userId, status);
        } else if ("completed".equals(event)) {
            status = 2; // 做种
            isSeeder = true;
            log.info("peer完成下载 - userId: {}, status: {}, seeder: {}", userId, status, isSeeder);
        } else {
            status = isSeeder ? 2 : 1; // 做种或下载中
            log.info("peer状态更新 - userId: {}, status: {}, seeder: {}", userId, status, isSeeder);
        }
        
        // 更新peer记录
        peer.setIp(ip);
        peer.setPort(port);
        peer.setUploaded(uploaded);
        peer.setDownloaded(downloaded);
        peer.setLeft(left);
        peer.setSeeder(isSeeder);
        peer.setLastAction(LocalDateTime.now());
        peer.setStatus(status);
        peer.setLastAnnounceTime(System.currentTimeMillis());
        peer.setUserAgent(userAgent);
        
        baseMapper.updateById(peer);
        log.info("更新peer记录 - userId: {}, status: {}, seeder: {}, left: {}", 
            userId, status, isSeeder, left);
        
        // 更新种子统计信息
        torrentService.updateTorrentStats(torrent.getId());
    }
    
    @Override
    @Transactional
    public void removePeer(String infoHash, Long userId) {
        // 获取种子信息
        Torrent torrent = torrentService.lambdaQuery()
                .eq(Torrent::getInfoHash, infoHash)
                .one();
        
        if (torrent != null) {
            LambdaQueryWrapper<Peer> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Peer::getTorrentId, torrent.getId())
                    .eq(Peer::getUserId, userId);
            this.remove(queryWrapper);
            
            // 更新种子统计信息
            torrentService.updateTorrentStats(torrent.getId());
        }
    }
    
    @Override
    public List<Peer> getPeers(String infoHash, Long excludeUserId, Integer maxPeers) {
        // 根据infoHash获取种子ID
        Torrent torrent = torrentService.lambdaQuery()
                .eq(Torrent::getInfoHash, infoHash)
                .one();
        
        if (torrent == null) {
            return Collections.emptyList();
        }
        
        LambdaQueryWrapper<Peer> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Peer::getTorrentId, torrent.getId())
                .gt(Peer::getLastAction, LocalDateTime.now().minusSeconds(TorrentConstant.PEER_TIMEOUT))
                .ne(excludeUserId != null, Peer::getUserId, excludeUserId)
                .orderByDesc(Peer::getLastAction)
                .last("LIMIT " + Math.min(maxPeers, TorrentConstant.MAX_PEERS));
        
        return list(queryWrapper);
    }
    
    @Override
    public int countSeeders(String infoHash) {
        Torrent torrent = torrentService.lambdaQuery()
                .eq(Torrent::getInfoHash, infoHash)
                .one();
        
        if (torrent == null) {
            return 0;
        }
        
        return Math.toIntExact(lambdaQuery()
                .eq(Peer::getTorrentId, torrent.getId())
                .eq(Peer::getSeeder, true)
                .gt(Peer::getLastAction, LocalDateTime.now().minusSeconds(TorrentConstant.PEER_TIMEOUT))
                .count());
    }
    
    @Override
    public int countLeechers(String infoHash) {
        Torrent torrent = torrentService.lambdaQuery()
                .eq(Torrent::getInfoHash, infoHash)
                .one();
        
        if (torrent == null) {
            return 0;
        }
        
        return Math.toIntExact(lambdaQuery()
                .eq(Peer::getTorrentId, torrent.getId())
                .eq(Peer::getSeeder, false)
                .gt(Peer::getLastAction, LocalDateTime.now().minusSeconds(TorrentConstant.PEER_TIMEOUT))
                .count());
    }
    
    @Override
    public Peer getUserPeer(String infoHash, Long userId) {
        Torrent torrent = torrentService.lambdaQuery()
                .eq(Torrent::getInfoHash, infoHash)
                .one();
        
        if (torrent == null) {
            return null;
        }
        
        return lambdaQuery()
                .eq(Peer::getTorrentId, torrent.getId())
                .eq(Peer::getUserId, userId)
                .one();
    }
    
    @Override
    public List<Peer> getAllPeersForInfoHash(String infoHash) {
        Torrent torrent = torrentService.lambdaQuery()
                .eq(Torrent::getInfoHash, infoHash)
                .one();
        
        if (torrent == null) {
            return new ArrayList<>();
        }
        
        return lambdaQuery()
                .eq(Peer::getTorrentId, torrent.getId())
                .list();
    }
    
    @Override
    @Scheduled(fixedRate = 600000) // 每10分钟执行一次
    public void cleanExpiredPeers() {
        LocalDateTime expireTime = LocalDateTime.now().minusSeconds(TorrentConstant.PEER_TIMEOUT);
        
        List<Peer> expiredPeers = lambdaQuery()
                .lt(Peer::getLastAction, expireTime)
                .list();
        
        if (!expiredPeers.isEmpty()) {
            // 删除过期Peer
            List<Long> peerIds = expiredPeers.stream().map(Peer::getId).collect(Collectors.toList());
            removeByIds(peerIds);
            
            // 更新相关种子的统计
            expiredPeers.stream()
                       .map(Peer::getTorrentId)
                       .distinct()
                       .forEach(torrentId -> {
                           Torrent torrent = torrentService.getById(torrentId);
                           if (torrent != null) {
                               updateTorrentPeerCounts(torrentId, torrent.getInfoHash());
                           }
                       });
            
            log.info("清理过期Peer: {} 个", expiredPeers.size());
        }
    }
    
    private void updateTorrentPeerCounts(Long torrentId, String infoHash) {
        int seeders = countSeeders(infoHash);
        int leechers = countLeechers(infoHash);
        torrentService.updateSeedersAndLeechers(torrentId, seeders, leechers);
    }
    
    private String generatePeerId() {
        byte[] peerId = new byte[20];
        // 生成客户端标识: -PT0001-
        String prefix = "-PT0001-";
        System.arraycopy(prefix.getBytes(), 0, peerId, 0, prefix.length());
        
        // 填充随机字节
        Random random = new Random();
        for (int i = prefix.length(); i < 20; i++) {
            peerId[i] = (byte) random.nextInt(256);
        }
        
        // 转换为十六进制字符串
        StringBuilder sb = new StringBuilder();
        for (byte b : peerId) {
            sb.append(String.format("%02x", b & 0xff));
        }
        return sb.toString();
    }
    
    @Override
    public List<Peer> getPeersByInfoHash(String infoHash, Integer limit) {
        Torrent torrent = torrentService.lambdaQuery()
                .eq(Torrent::getInfoHash, infoHash)
                .one();
        
        if (torrent == null) {
            return new ArrayList<>();
        }
        
        return lambdaQuery()
                .eq(Peer::getTorrentId, torrent.getId())
                .last("LIMIT " + limit)
                .list();
    }
    
    @Override
    public List<Peer> getPeersForTorrent(String infoHash, Integer numwant) {
        // 查找种子
        Torrent torrent = torrentService.lambdaQuery()
                .eq(Torrent::getInfoHash, infoHash)
                .one();
        
        if (torrent == null) {
            return new ArrayList<>();
        }
        
        // 获取peer列表
        return lambdaQuery()
                .eq(Peer::getTorrentId, torrent.getId())
                .last("ORDER BY RAND() LIMIT " + numwant)
                .list();
    }
} 